In [1]:
a = {"x" : 1, "z" : 3}
b = {"y" : 2, "z" : 4}
现在假设你必须在两个字典中执行查找操作(比如先从 a
中找,如果找不到再在 b
中找)。 一个非常简单的解决方案就是使用 collections
模块中的 ChainMap
类。比如:
In [2]:
from collections import ChainMap
c = ChainMap(a, b)
print(c["x"])
In [3]:
print(c["y"])
In [4]:
print(c["z"])
讨论
一个 ChainMap
接受多个字典并将它们在逻辑上变为一个字典。 然后,这些字典并不是真的合并在一起了, ChainMap
类只是在内部创建了一个容纳这些字典的列表 并重新定义了一些常见的字典操作来遍历这个列表。大部分字典操作都是可以正常使用的,比如:
In [5]:
len(c)
Out[5]:
In [6]:
list(c.keys())
Out[6]:
In [7]:
list(c.values())
Out[7]:
如果出现重复键,那么第一次出现的映射值会被返回。 因此,例子程序中的 c['z']
总是会返回字典 a
中对应的值,而不是 b
中对应的值。
对于字典的更新或删除操作总是影响的是列表中第一个字典。比如:
In [8]:
c["z"] = 10
c["w"] = 40
In [9]:
del c["x"]
In [10]:
a
Out[10]:
In [11]:
del c["y"]
ChainMap
对于编程语言中的作用范围变量(比如 globals
, locals
等)是非常有用的。 事实上,有一些方法可以使它变得简单:
In [12]:
values = ChainMap()
values["x"] = 1
In [13]:
# Add a new mapping
values = values.new_child()
In [14]:
values["x"] = 2
In [15]:
# Add a new mapping
values = values.new_child()
values["x"] = 3
In [16]:
values
Out[16]:
In [17]:
values["x"]
Out[17]:
In [18]:
# Discard last mapping
values = values.parents
values["x"]
Out[18]:
In [19]:
values = values.parents
values["x"]
Out[19]:
In [20]:
values
Out[20]:
作为 ChainMap
的替代,你可能会考虑使用 update()
方法将两个字典合并。比如:
In [21]:
a = {"x" : 1, "z" : 3}
b = {"y" : 2, "z" : 4}
merged = dict(b)
merged
Out[21]:
In [22]:
merged.update(a)
merged
Out[22]:
In [23]:
merged["x"]
Out[23]:
In [24]:
merged["y"]
Out[24]:
In [25]:
merged["z"]
Out[25]:
这样也能行得通,但是它需要你创建一个完全不同的字典对象(或者是破坏现有字典结构)。 同时,如果原字典做了更新,这种改变不会反应到新的合并字典中去。比如:
In [26]:
a["x"] = 13
merged["x"]
Out[26]:
ChainMap
使用原来的字典,它自己不创建新的字典。所以它并不会产生上面所说的结果,比如:
In [27]:
a = {"x" : 1, "z" : 3}
b = {"y" : 2, "z" : 4}
merged = ChainMap(a, b)
merged
Out[27]:
In [28]:
merged["x"]
Out[28]:
In [29]:
a["x"] = 42
merged["x"]
Out[29]: